#include "i2c_stm32l4xx.h"

static int32_t Stm32xxI2cTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count)
{
    int32_t ret = HDF_SUCCESS; 
    int16_t index = 0;
    struct Stm32xxI2cCntlr *stm32xx = NULL; 
    
    if (cntlr == NULL || cntlr->priv == NULL) {
        HDF_LOGE("Stm32xxI2cTransfer: cntlr lor stm32xx is null!");
        return HDF_ERR_INVALID_OBJECT;
    }

    stm32xx = (struct Stm32xxI2cCntlr *)cntlr;
    // printf("stm32xx->i2cHandle->Instance: %x\n",stm32xx->i2cHandle->Instance);//检查地址

    if (msgs == NULL || count <= 0) {
        HDF_LOGE("Stm32xxI2cTransfer: err parms! count:%d", count);
        return HDF_ERR_INVALID_PARAM;
    } 
    
    while (index < count) {
        if (msgs->flags & I2C_FLAG_READ) {
            printf("begin Receive: \n");
            ret = HAL_I2C_Master_Receive(stm32xx->i2cHandle, msgs->addr, msgs->buf, msgs->len, STM32L4XX_I2C_TIMEOUT);
        } else {
            printf("begin transmit\n");
            ret = HAL_I2C_Master_Transmit(stm32xx->i2cHandle, msgs->addr, msgs->buf, msgs->len , STM32L4XX_I2C_TIMEOUT);
        }
        if (ret != HAL_OK) {
            printf("%s: i2c hal transmit fail:%d\n", __func__, ret);
            ret =  HDF_FAILURE;
        }
        index++;
    }
    return  ret; //(index > 0) ? HDF_SUCCESS :
}

static const struct I2cMethod g_method = {
    .transfer = Stm32xxI2cTransfer,
};

static int32_t Stm32xxI2cLock(struct I2cCntlr *cntlr)
{
    struct Stm32xxI2cCntlr *stm32xx = (struct Stm32xxI2cCntlr *)cntlr;
    if (stm32xx != NULL) {
        return OsalSpinLock(&stm32xx->spin);
    }
    return HDF_SUCCESS;
}

static void Stm32xxI2cUnlock(struct I2cCntlr *cntlr)
{
    struct Stm32xxI2cCntlr *stm32xx = (struct Stm32xxI2cCntlr *)cntlr;
    if (stm32xx != NULL) {
        (void)OsalSpinUnlock(&stm32xx->spin);
    }
}

static const struct I2cLockMethod g_lockOps = {
    .lock = Stm32xxI2cLock,
    .unlock = Stm32xxI2cUnlock,
};

// Init 函数实现部分

I2C_TypeDef *Stm32l4xxGetI2cInstance(int16_t number)
{
    printf("I2C_TypeDef : %d \n",number);
    if (number < 1 || number > 4) {
        return NULL;
    }
    switch (number) {
        case 1:
            return I2C1;
        case 3:
            return I2C3;
        default:
            break;
    }
    return NULL;
}
 
static void Stm32xxI2cHandleInit(struct Stm32xxI2cCntlr *stm32xx)
{ 
    I2C_HandleTypeDef *i2cHandle = (struct I2C_HandleTypeDef *)OsalMemCalloc(sizeof(*i2cHandle));
    
    stm32xx->i2cHandle = i2cHandle;
    // if(i2cHandle->Instance == NULL) {
    //     printf("i2cHandle->Instance ==NULL ");//this is right 
    // } else {
    //     printf("i2cHandle->Instance = %x ",i2cHandle->Instance);
    // }
    // printf("i2cHandle->Instance %x ",i2cHandle->Instance);

    i2cHandle->Instance = Stm32l4xxGetI2cInstance(stm32xx->bus);
    if (i2cHandle->Instance == NULL) {
        printf("%s: get inst of bus:%u failed!", __func__, stm32xx->bus);
        HDF_LOGE("%s: get inst of bus:%u failed!", __func__, stm32xx->bus);
        return HDF_FAILURE;
    }
    // printf("after %x\n",i2cHandle->Instance);
    i2cHandle->Init.Timing = 0x307075B1;
    i2cHandle->Init.OwnAddress1 = 0;
    i2cHandle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    i2cHandle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    i2cHandle->Init.OwnAddress2 = 0;
    i2cHandle->Init.OwnAddress2Masks = I2C_OA2_NOMASK;
    i2cHandle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    i2cHandle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(i2cHandle) != HAL_OK)
    {
        printf("HAL_I2C_Init fail \n");
        Error_Handler();
    }
    /** Configure Analogue filter
     */
    if (HAL_I2CEx_ConfigAnalogFilter(i2cHandle, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
    {
        printf("HAL_I2CEx_ConfigAnalogFilter fail \n");
        Error_Handler();
    }
    /** Configure Digital filter
     */
    if (HAL_I2CEx_ConfigDigitalFilter(i2cHandle, 0) != HAL_OK)
    {
        printf("HAL_I2CEx_ConfigDigitalFilter fail \n");
        Error_Handler();
    }
}

static int32_t Stm32xxI2cReadDrs(struct Stm32xxI2cCntlr *stm32xx, const struct DeviceResourceNode *node)
{
    int32_t ret;
    struct DeviceResourceIface *drsOps = NULL;

    drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    if (drsOps == NULL || drsOps->GetUint32 == NULL) {
        HDF_LOGE("%s: invalid drs ops fail!", __func__);
        return HDF_FAILURE;
    }

    ret = drsOps->GetUint32(node, "freq", &stm32xx->freq, 0);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: read freq fail!", __func__);
        return ret;
    }

    ret = drsOps->GetUint32(node, "irq", &stm32xx->irq, 0);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: read irq fail!", __func__);
        return ret;
    }

    ret = drsOps->GetUint32(node, "clk", &stm32xx->clk, 0);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: read clk fail!", __func__);
        return ret;
    }

    ret = drsOps->GetUint16(node, "bus", (uint16_t *)&stm32xx->bus, 0);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: read bus fail!", __func__);
        return ret;
    }
    //printf("stm32xx->clk %d,stm32xx->bus %d\n",stm32xx->clk,stm32xx->bus);
    return HDF_SUCCESS;
}

static int32_t Stm32xxI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
{
    int32_t ret;
    struct Stm32xxI2cCntlr *stm32xx = NULL;
    (void)device;

    stm32xx = (struct Stm32xxI2cCntlr *)OsalMemCalloc(sizeof(*stm32xx));
    if (stm32xx == NULL) {
        HDF_LOGE("%s: malloc stm32xx fail!", __func__);
        return HDF_ERR_MALLOC_FAIL;
    }

    ret = Stm32xxI2cReadDrs(stm32xx, node);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: read drs fail! ret:%d", __func__, ret);
        goto __ERR__;
    }
    

    Stm32xxI2cHandleInit(stm32xx);
    // printf("stm32xx->i2cHandle->Instance : %x,I2C1: %x \n",stm32xx->i2cHandle->Instance,I2C1);

    stm32xx->cntlr.priv = (void *)node;
    stm32xx->cntlr.busId = stm32xx->bus;
    stm32xx->cntlr.ops = &g_method;
    stm32xx->cntlr.lockOps = &g_lockOps;
    (void)OsalSpinInit(&stm32xx->spin);
    ret = I2cCntlrAdd(&stm32xx->cntlr);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: add i2c controller fail:%d!", __func__, ret);
        (void)OsalSpinDestroy(&stm32xx->spin);
        goto __ERR__;
    }

    return HDF_SUCCESS;
__ERR__:
    if (stm32xx != NULL) {
        OsalMemFree(stm32xx);
        stm32xx = NULL;
    }
    return ret;
}

static int32_t Stm32xxI2cInit(struct HdfDeviceObject *device)
{
    int32_t ret;
    const struct DeviceResourceNode *childNode = NULL;

    HDF_LOGE("%s: Enter", __func__);
    if (device == NULL || device->property == NULL) {
        HDF_LOGE("%s: device or property is NULL", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    ret = HDF_SUCCESS;
    printf("i2c entering successful \n");
    DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
        ret = Stm32xxI2cParseAndInit(device, childNode);
        if (ret != HDF_SUCCESS) {
            break;
        }
    }

    return ret;
}

// Release 函数实现部分 

static void Stm32xxI2cHandleDeInit(struct Stm32xxI2cCntlr *stm32xx)
{
    I2C_HandleTypeDef *i2cHandle = stm32xx->i2cHandle;
    if(i2cHandle == NULL) {        
        HDF_LOGE("%s: i2cHandle is null", __func__);
        return;
    }
    (void)OsalSpinDestroy(&stm32xx->spin);
    HAL_I2C_DeInit(i2cHandle);
    OsalMemFree(stm32xx->i2cHandle);
    OsalMemFree(stm32xx);
}

static void Stm32xxI2cRemoveByNode(const struct DeviceResourceNode *node)
{
    int32_t ret;
    int16_t bus;
    struct I2cCntlr *cntlr = NULL;
    struct Stm32xxI2cCntlr *stm32xx = NULL;
    struct DeviceResourceIface *drsOps = NULL;

    drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    if (drsOps == NULL || drsOps->GetUint32 == NULL) {
        HDF_LOGE("%s: invalid drs ops fail!", __func__);
        return;
    }

    ret = drsOps->GetUint16(node, "bus", (uint16_t *)&bus, 0);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: read bus fail!", __func__);
        return;
    }

    cntlr = I2cCntlrGet(bus);
    if (cntlr != NULL && cntlr->priv == node) {
        I2cCntlrPut(cntlr);
        I2cCntlrRemove(cntlr);
        stm32xx = (struct Stm32xxI2cCntlr *)cntlr;
        Stm32xxI2cHandleDeInit(stm32xx);
    }
    return;
}


static void Stm32xxI2cRelease(struct HdfDeviceObject *device)
{
    const struct DeviceResourceNode *childNode = NULL;

    HDF_LOGI("%s: enter", __func__);

    if (device == NULL || device->property == NULL) {
        HDF_LOGE("%s: device or property is NULL", __func__);
        return;
    }

    printf("i2c release successful \n");
    DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
        Stm32xxI2cRemoveByNode(childNode);
    }
}

struct HdfDriverEntry g_i2cDriverEntry = {
    .moduleVersion = 1,
    .Init = Stm32xxI2cInit,
    .Release = Stm32xxI2cRelease,
    .moduleName = "stm32l4xx_i2c_driver",
};
HDF_INIT(g_i2cDriverEntry);